home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / admin / linuxcon.000 / linuxcon / linuxconf-1.6 / netconf / ipfwrule.c < prev    next >
C/C++ Source or Header  |  1996-08-03  |  12KB  |  527 lines

  1. #include <string.h>
  2. #include <stdlib.h>
  3.     #include <sys/types.h>
  4.     #include <sys/socket.h>
  5.     #include <netinet/in.h>
  6.     #include <linux/ip.h>
  7.     #include <linux/tcp.h>
  8.     #include <linux/udp.h>
  9.     #include <linux/icmp.h>
  10.     #include <linux/if.h>
  11.     #include <linux/ip_fw.h>
  12. #include <limits.h>
  13. #include <netdb.h>
  14. #include "netconf.h"
  15. #include "internal.h"
  16. #include "firewall.h"
  17. #include "../dialog/dialog.h"
  18. #include "../misc/misc.h"
  19. #include "../userconf/userconf.h"
  20. #include "../paths.h"
  21. #include "netconf.m"
  22.  
  23. #ifndef IP_FW_POLICY_IN
  24.     /* These are just here so it compiles */
  25.     #define IP_FW_F_MASQ        0
  26.     #define IP_FW_APPEND_OUT    1
  27.     #define IP_FW_APPEND_IN        2
  28.     #define IP_FW_APPEND_FWD    3
  29.  
  30.     #define FIREWAALL_NONE
  31. #endif
  32.  
  33. NETCONF_HELP_FILE help_ipfw ("firewall");
  34.  
  35.  
  36. PROTECTED IPFW_RULE::IPFW_RULE()
  37. {
  38.     from.interface.setfrom ("Any");
  39.     to.interface.setfrom ("Any");
  40.     protocol.setfrom ("all");
  41.     /* #Specification: netconf / firewalling / active rule
  42.         One rule may be defined and desactivated without erasing it.
  43.         This give some flexibility to the administrator to define
  44.         complex rules and "comment out" some.
  45.     */
  46.     active = 1;
  47. }
  48. /*
  49.     Extract a number from a buffer.
  50.     The number may be enclosed in double quote.
  51. */
  52. static const char *firewall_extract (const char *buf, char &val)
  53. {
  54.     SSTRING s;
  55.     buf = str_extract (buf,s);
  56.     val = s.getval();
  57.     return buf;
  58. }
  59.  
  60. static const char *firewall_extract (const char *buf, IPFW_SRC &s)
  61. {
  62.     buf = str_extract (buf,s.host);
  63.     buf = str_extract (buf,s.netmask);
  64.     buf = str_extract (buf,s.portrange);
  65.     buf = str_extract (buf,s.ports);
  66.     buf = str_extract (buf,s.interface);
  67.     return buf;
  68. }
  69.  
  70. PROTECTED IPFW_RULE::IPFW_RULE(const char * &buf)
  71. {
  72.     buf = firewall_extract (buf,active);
  73.     buf = str_extract (buf,protocol);
  74.     buf = firewall_extract (buf,from);
  75.     buf = firewall_extract (buf,to);
  76. }
  77.  
  78. PUBLIC IPFW_RULE_FORWARD::IPFW_RULE_FORWARD(const char *buf)
  79.     : IPFW_RULE (buf)
  80. {
  81.     firewall_extract (buf,masquerade);
  82. }
  83. PUBLIC IPFW_RULE_FORWARD::IPFW_RULE_FORWARD()
  84. {
  85.     masquerade = 0;
  86. }
  87.  
  88. PUBLIC IPFW_RULE_OUTPUT::IPFW_RULE_OUTPUT(const char *buf)
  89.     : IPFW_RULE (buf)
  90. {
  91. }
  92. PUBLIC IPFW_RULE_OUTPUT::IPFW_RULE_OUTPUT()
  93. {
  94. }
  95.  
  96. PUBLIC IPFW_RULE_INPUT::IPFW_RULE_INPUT(const char *buf)
  97.     : IPFW_RULE (buf)
  98. {
  99. }
  100. PUBLIC IPFW_RULE_INPUT::IPFW_RULE_INPUT()
  101. {
  102. }
  103.  
  104. static void firewall_append (char *buf, SSTRING &s)
  105. {
  106.     strcat (buf," \"");
  107.     strcat (buf,s.get());
  108.     strcat (buf,"\"");
  109. }
  110.  
  111. static void firewall_append (char *buf, int val)
  112. {
  113.     char valstr[20];
  114.     sprintf (valstr,"%d",val);
  115.     strcat (buf," \"");
  116.     strcat (buf,valstr);
  117.     strcat (buf,"\"");
  118. }
  119.  
  120. static void firewall_append (char *buf, IPFW_SRC &s)
  121. {
  122.     firewall_append (buf,s.host);
  123.     firewall_append (buf,s.netmask);
  124.     firewall_append (buf,s.portrange);
  125.     firewall_append (buf,s.ports);
  126.     firewall_append (buf,s.interface);
  127. }
  128.  
  129. char FIREWALL[] = "firewall";
  130. char FORWARD[]  = "forward";
  131. char BLOCK[]  = "block";
  132. char OUTPUT[]  = "output";
  133.  
  134. /*
  135.     Save one forward line in /etc/conf.linuxconf
  136. */
  137. PROTECTED void IPFW_RULE::savek(char *buf)
  138. {
  139.     buf[0] = '\0';
  140.     firewall_append (buf,active);
  141.     firewall_append (buf,protocol);
  142.     firewall_append (buf,from);
  143.     firewall_append (buf,to);
  144. }
  145.  
  146. /*
  147.     Save one forward line in /etc/conf.linuxconf
  148. */
  149. PUBLIC void IPFW_RULE_FORWARD::save()
  150. {
  151.     char buf[2000];
  152.     IPFW_RULE::savek(buf);
  153.     firewall_append (buf,masquerade);
  154.     linuxconf_add (FIREWALL,FORWARD,buf);
  155. }
  156. /*
  157.     Save one forward line in /etc/conf.linuxconf
  158. */
  159. PUBLIC void IPFW_RULE_INPUT::save()
  160. {
  161.     char buf[2000];
  162.     IPFW_RULE::savek(buf);
  163.     linuxconf_add (FIREWALL,BLOCK,buf);
  164. }
  165. /*
  166.     Save one output line in /etc/conf.linuxconf
  167. */
  168. PUBLIC void IPFW_RULE_OUTPUT::save()
  169. {
  170.     char buf[2000];
  171.     IPFW_RULE::savek(buf);
  172.     linuxconf_add (FIREWALL,OUTPUT,buf);
  173. }
  174.  
  175. /*
  176.     Format the minimum information about the rule so it will
  177.     be presentable in a menu.
  178. */
  179. PUBLIC void IPFW_RULE::present (char *buf)
  180. {
  181.     sprintf (buf,"[%c] %-4s %4s:%-10s <-> %4s:%-10s"
  182.         ,active ? 'X' : ' '
  183.         ,protocol.get()
  184.         ,from.interface.get()
  185.         ,from.host.get()
  186.         ,to.interface.get()
  187.         ,to.host.get());
  188. }
  189.  
  190. static void ipfwrule_computemsk (const char ip[], char msk[])
  191. {
  192.     int num4[4];
  193.     device_aip24 (ip,num4);
  194.     if (num4[3] != 0){
  195.         strcpy (msk,"255.255.255.255");
  196.     }else{
  197.         char std_net[20];
  198.         device_setstdnetmask(ip,std_net,msk);
  199.     }
  200. }
  201. /*
  202.     try to convert something into an IP number
  203.     Return -1 if it can't.
  204. */
  205. int ipfwrule_convert (
  206.     const char *str,    // An IP number, a host name or an interface
  207.                 // name (eth0)
  208.     char ip[],
  209.     char msk[])        // Corresponding (computed) netmask
  210.                 // or extracted from the device
  211. {
  212.     int ret = 0;
  213.     struct hostent *hent;
  214.     struct netent *nent;
  215.     IFCONFIG_INFO info;
  216.     if (device_validip(str,false)){
  217.         strcpy (ip,str);
  218.         ipfwrule_computemsk (str,msk);
  219.     }else if (ifconfig_getinfo(str,info)!=-1){
  220.         // This is a network devices and we must
  221.         // pick the IP number since ipfw don't do it.
  222.         strcpy (ip,info.ip_addr);
  223.         strcpy (msk,info.netmask);
  224.     }else if ((hent = gethostbyname(str)) != NULL){
  225.         devices_ip2a (hent,ip);
  226.         ipfwrule_computemsk (ip,msk);
  227.     }else if ((nent = getnetbyname(str)) != NULL){
  228.         devices_ip2a (nent,ip);
  229.         ipfwrule_computemsk (ip,msk);
  230.     }else{
  231.         ret = -1;
  232.     }
  233.     return ret;
  234. }
  235.  
  236. /*
  237.     try to convert something into an IP number
  238.     Return -1 if it can't.
  239. */
  240. static int ipfwrule_convert (
  241.     const char *str,    // An IP number, a host name or an interface
  242.                 // name (eth0)
  243.     char ip[])
  244. {
  245.     char msk[16];
  246.     return ipfwrule_convert (str,ip,msk);
  247. }
  248. /*
  249.     Return the number of significative bits in the netmask (1's)
  250.  
  251.     Return -1 if any error.
  252. */
  253. PUBLIC int IPFW_RULE::nbbitmask(IPFW_SRC &f)
  254. {
  255.     int ret = f.nbbit_msk;
  256.     if (ret == -1){
  257.         const char *msk = f.netmask.get();
  258.         char std_msk[20];
  259.         if (*msk == '\0'){
  260.             /* #Specification: firewall / netmask
  261.                 The netmask is optionnal. It is automacly
  262.                 compute from the host/network number
  263.             */
  264.             char ip[20];
  265.             if (ipfwrule_convert(f.host.get(),ip,std_msk)!=-1){
  266.                 msk = std_msk;
  267.             }else{
  268.                 ret = -1;
  269.             }
  270.         }
  271.         int num4[4];
  272.         device_aip24 (msk,num4);
  273.         unsigned long nmsk = (num4[0] << 24) | (num4[1] << 16)
  274.             | (num4[2] << 8) | num4[3];
  275.         unsigned long cmp = 0x80000000l;
  276.         int i;
  277.         for (i=0; i<32 && (nmsk & cmp) != 0; i++, cmp >>= 1);
  278.         ret = i;
  279.         f.nbbit_msk = ret;
  280.     }
  281.     return ret;
  282. }
  283.  
  284. /*
  285.     Return the number of significative bits in the netmask (1's)
  286.  
  287.     This is taken in the from.
  288. */
  289. PUBLIC int IPFW_RULE::nbbitmask_from()
  290. {
  291.     return nbbitmask (from);
  292. }
  293. /*
  294.     Return the number of significative bits in the netmask (1's)
  295.  
  296.     This is taken in the "to".
  297. */
  298. PUBLIC int IPFW_RULE::nbbitmask_to()
  299. {
  300.     return nbbitmask (to);
  301. }
  302. /*
  303.     Return -1 if abort
  304.     Return  0 if accept
  305.     Return  1 if delete required
  306. */
  307. PUBLIC int IPFW_RULE::editk(
  308.     DIALOG &dia,
  309.     const char *title)
  310. {
  311.     dia.newf_chk ("",active,MSG_U(F_RULEACTIVE,"This rule is active"));
  312.     int i;
  313.     FIELD_COMBO *comb = dia.newf_combo (MSG_U(F_PROTOCOL,"Protocol")
  314.         ,protocol);
  315.     for (i=0; i<4; i++){
  316.         static const char *tbproto[]={
  317.             "icmp","udp","tcp","all"
  318.         };
  319.         comb->addopt (tbproto[i]);
  320.     }
  321.  
  322.     static const char *tbinter[][2]={
  323.         {"Any",    MSG_U(F_PACKFROMANY,"Packet come from anywhere") },
  324.         {"eth0",    MSG_U(F_FIRSTETH,"First ethernet adaptor")},
  325.         {"eth1",    MSG_U(F_SECOND,"Second")},
  326.         {"eth2",    MSG_U(F_THIRD,"Third")},
  327.         {"eth3",    MSG_U(F_FOURTH,"Fourth")},
  328.         {"sl0",        MSG_U(F_FIRSTSLIP,"First SLIP/CSLIP channel")},
  329.         {"sl1",        MSG_R(F_SECOND)},
  330.         {"ppp0",    MSG_U(F_FIRSTPPP,"First PPP channel")},
  331.         {"ppp1",    MSG_R(F_SECOND)},
  332.     };
  333.  
  334.     dia.newf_title ("",MSG_U(F_FROM,"From"));
  335.     dia.newf_str (MSG_U(F_HOSTORNET,"Host or Network"),from.host);
  336.     dia.newf_str (MSG_U(F_HNETMASK,"Netmask"),from.netmask);
  337.     dia.newf_str (MSG_U(F_PORTRANGE,"Port range"),from.portrange);
  338.     dia.newf_str (MSG_U(F_OTHERPORTS,"Other ports"),from.ports);
  339.     comb = dia.newf_combo (MSG_U(F_INTERFACE,"Interface"),from.interface);
  340.     for (i=0; i<9; i++){
  341.         comb->addopt (tbinter[i][0],tbinter[i][1]);
  342.     }
  343.  
  344.     dia.newf_title ("",MSG_U(F_TO,"To"));
  345.     dia.newf_str (MSG_R(F_HOSTORNET),to.host);
  346.     dia.newf_str (MSG_R(F_HNETMASK),to.netmask);
  347.     dia.newf_str (MSG_R(F_PORTRANGE),to.portrange);
  348.     dia.newf_str (MSG_R(F_OTHERPORTS),to.ports);
  349.  
  350.     comb = dia.newf_combo (MSG_R(F_INTERFACE),to.interface);
  351.     for (i=0; i<9; i++){
  352.         comb->addopt (tbinter[i][0],tbinter[i][1]);
  353.     }
  354.     int ret = -1;
  355.     int nof = 0;
  356.     while (1){
  357.         MENU_STATUS code = dia.edit (title
  358.             ,""
  359.             ,help_ipfw.getpath()
  360.             ,nof
  361.             ,MENUBUT_CANCEL|MENUBUT_ACCEPT|MENUBUT_DEL);
  362.         if (code == MENU_ESCAPE || code == MENU_CANCEL){
  363.             break;
  364.         }else if (code == MENU_DEL){
  365.             ret = 1;
  366.             break;
  367.         }else{
  368.             ret = 0;
  369.             break;
  370.         }
  371.     }
  372.     if (ret != 0) dia.restore();
  373.     return ret;
  374. }
  375.  
  376. /*
  377.     Return -1 if abort
  378. */
  379. PUBLIC int IPFW_RULE_FORWARD::edit()
  380. {
  381.     DIALOG dia;
  382.     dia.newf_chk ("",masquerade,MSG_U(F_DOMASQUERADE,"Do masquerading"));
  383.     return IPFW_RULE::editk (dia,MSG_U(T_FORWARDING,"Firewall forwarding rule"));
  384. }
  385. /*
  386.     Return -1 if abort
  387. */
  388. PUBLIC int IPFW_RULE_OUTPUT::edit()
  389. {
  390.     DIALOG dia;
  391.     return IPFW_RULE::editk (dia,MSG_U(T_OUTPUT,"Firewall Outputing rule"));
  392. }
  393. /*
  394.     Return -1 if abort
  395. */
  396. PUBLIC int IPFW_RULE_INPUT::edit()
  397. {
  398.     DIALOG dia;
  399.     return IPFW_RULE::editk (dia,MSG_U(T_INPUTING,"Firewall inputing rule"));
  400. }
  401.  
  402. PUBLIC int IPFW_RULE::setup(
  403.     IPFW_SRC &f,
  404.     IPFW_SRC &t,
  405.     const char *type,
  406.     int doit,        // Exec the command ?
  407.     SSTRING *collect)    // Will contain a copy of the
  408.                 // command generated
  409. {
  410.     int ret = 0;
  411.     if (active){
  412.         char interbuf[100];
  413.         strcpy (interbuf,"0.0.0.0");
  414.         if (!f.interface.is_empty()
  415.             && f.interface.cmp("Any")!=0){
  416.             /* #Specification: firewall / iface argument
  417.                 We accept a host name, an IP number or
  418.                 a network device name (eth0).
  419.             */
  420.             char ip[20];
  421.             const char *ifacearg = f.interface.get();
  422.             if (ipfwrule_convert (ifacearg,ip)!=-1){
  423.                 sprintf (interbuf,"%s",ip);
  424.             }else{
  425.                 xconf_error (MSG_U(E_IVLDINTER
  426.                     ,"Invalid interface %s for firewalling rule")
  427.                     ,ifacearg);
  428.                 ret = -1;
  429.             }
  430.         }
  431.         /* #Specification: firewall / forwarding / accept
  432.             The firewalling interface support only accepting rule
  433.             so far. It is expect to be enough for most firewalls.
  434.  
  435.             Supporting denying and rejecting is not much of a problem
  436.             although, Experience will shows us how to do this
  437.             without confusing the user...
  438.  
  439.             Comments are welcome.
  440.         */
  441.         char fhoststr[PATH_MAX],fhostmsk[16];
  442.         ret |= ipfwrule_convert (f.host.get(),fhoststr,fhostmsk);
  443.         char thoststr[PATH_MAX],thostmsk[16];
  444.         ret |= ipfwrule_convert (t.host.get(),thoststr,thostmsk);
  445.         struct ip_fw bf;
  446.         if (ipfw_baseinit(interbuf,protocol.get()
  447.             ,fhoststr,f.netmask.is_empty() ? fhostmsk : f.netmask.get()
  448.             ,f.portrange.get(),f.ports.get()
  449.             ,thoststr,t.netmask.is_empty() ? thostmsk : t.netmask.get()
  450.             ,t.portrange.get(),t.ports.get()
  451.             ,bf)!=-1){
  452.             int command = 0;
  453.             if (type[0] == 'm'){
  454.                 command = IP_FW_APPEND_FWD;
  455.                 bf.fw_flg |= IP_FW_F_MASQ;
  456.             }else if (type[0] == 'f'){
  457.                 command = IP_FW_APPEND_FWD;
  458.             }else if (type[0] == 'o'){
  459.                 command = IP_FW_APPEND_OUT;
  460.             }else if (type[0] == 'b'){
  461.                 command = IP_FW_APPEND_IN;
  462.             }
  463.             ret = ipfw_append (doit,collect,command,bf);
  464.         }else{
  465.             ret = -1;
  466.         }
  467.     }
  468.     return ret;
  469. }
  470.  
  471. /*
  472.     Setup one side of the forwarding rule (from -> to)
  473. */
  474. PUBLIC int IPFW_RULE_FORWARD::setup_left(int doit, SSTRING *collect)
  475. {
  476.     int ret = -1;
  477.     if (masquerade){
  478.         ret = setup (from,to,"m",doit,collect);
  479.     }else{
  480.         ret = setup (from,to,"f",doit,collect);
  481.     }
  482.     return ret;
  483. }
  484. /*
  485.     Setup one side of the forwarding rule (to -> from)
  486. */
  487. PUBLIC int IPFW_RULE_FORWARD::setup_right(int doit, SSTRING *collect)
  488. {
  489.     int ret = 0;
  490.     if (!masquerade){
  491.         ret = setup (to,from,"f",doit,collect);
  492.     }
  493.     return ret;
  494. }
  495. /*
  496.     Setup one side of the forwarding rule (from -> to)
  497. */
  498. PUBLIC int IPFW_RULE_OUTPUT::setup_left(int doit, SSTRING *collect)
  499. {
  500.     return setup (from,to,"o",doit,collect);
  501. }
  502. /*
  503.     Setup one side of the forwarding rule (to -> from)
  504. */
  505. PUBLIC int IPFW_RULE_OUTPUT::setup_right(int doit, SSTRING *collect)
  506. {
  507.     return setup (to,from,"o",doit,collect);
  508. }
  509.  
  510.  
  511. /*
  512.     Setup one side of the blocking rule (from -> to)
  513. */
  514. PUBLIC int IPFW_RULE_INPUT::setup_left(int doit, SSTRING *collect)
  515. {
  516.     return setup (from,to,"b",doit,collect);
  517. }
  518. /*
  519.     Setup one side of the blocking rule (to -> from)
  520. */
  521. PUBLIC int IPFW_RULE_INPUT::setup_right(int doit, SSTRING *collect)
  522. {
  523.     return setup (to,from,"b",doit,collect);
  524. }
  525.  
  526.  
  527.